package com.xxxx.server.service.impl;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxxx.server.exceptions.MyException;
import com.xxxx.server.mapper.AdminMapper;
import com.xxxx.server.mapper.AdminRoleMapper;
import com.xxxx.server.mapper.RoleMapper;
import com.xxxx.server.pojo.Admin;
import com.xxxx.server.pojo.AdminRole;
import com.xxxx.server.pojo.Role;
import com.xxxx.server.pojo.param.AdminParam;
import com.xxxx.server.pojo.param.BackPasswordParam;
import com.xxxx.server.pojo.param.UpdUserParam;
import com.xxxx.server.service.IAdminService;
import com.xxxx.server.service.IFileUploadService;
import com.xxxx.server.utils.AnyUtil;
import com.xxxx.server.utils.AssertUtil;
import com.xxxx.server.utils.JwtUtils;
import com.xzl.tool.util.RespBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zhoubin
 * @since 2020-10-15
 */
@Service
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements IAdminService {

    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private JwtUtils jwtUtils;

    @Value("${spring.tengxun.path}")
    private String path;
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Resource
    private AdminMapper adminMapper;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private AdminRoleMapper adminRoleMapper;
    @Resource
    private IFileUploadService fileUploadService;
    @Resource
    private RedisTemplate redisTemplate;

    private final String ADMIN_ROLE_ZH = "系统管理员";//管理员角色名

    /**
     * 登录
     *
     * @param username
     * @param password
     * @return
     */
    @Override
    public RespBean login(String username, String password) {
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        //判断用户是否存在
        if (null == userDetails || !passwordEncoder.matches(password, userDetails.getPassword())) {
            throw new UsernameNotFoundException("用户名或密码不正确");
        }
        //判断用户是否启用
        if (!userDetails.isEnabled()) {
            return RespBean.error("用户尚未启用，请联系管理员");
        }
        //将当前用户对象存入SpringSecurity全局上下文，方便其他方法使用
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails,
                null, userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        //生成token并返回
        String token = jwtUtils.generatorToken(userDetails);
        Map<String, Object> tokenMap = new HashMap<>();
        tokenMap.put("tokenHead", tokenHead);
        tokenMap.put("token", token);
        return RespBean.success("登录成功", tokenMap);
    }

    /**
     * 根据用户名获取用户信息
     *
     * @param username
     * @return
     */
    @Override
    public Admin getUserByUsername(String username) {
        Admin admin = adminMapper.selectByUserName(username);
        AssertUtil.isTrue(null == admin, "该用户不存在");
        return admin;
    }

    @Override
    public RespBean login(String username, String password, String code, HttpServletRequest request) {
        //获取内容
        String captcha = (String) request.getSession().getAttribute("captcha");
        System.out.println(captcha);
        if (StringUtils.isBlank(captcha))
            throw new MyException("验证码已过期!");
        //忽略大小写进行比对
        if (StringUtils.isBlank(code) || !captcha.equals(code)) {
            return RespBean.error("验证码填写错误！");
        }
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        if (null == userDetails || !passwordEncoder.matches(password,
                userDetails.getPassword())) {
            return RespBean.error("用户名或密码不正确!");
        }
        if (!userDetails.isEnabled()) {
            return RespBean.error("账号被禁用，请联系管理员!");
        }
        UsernamePasswordAuthenticationToken authentication =
                new UsernamePasswordAuthenticationToken(userDetails, null,
                        userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
        String token = jwtUtils.generatorToken(userDetails);
        Map<String, String> tokenMap = new HashMap<>();
        tokenMap.put("token", token);
        tokenMap.put("tokenHead", tokenHead);
        return RespBean.success("登录成功", tokenMap);
    }

    @Override
    public List<Role> getRoles(Integer id) {
        return roleMapper.getRoles(id);
    }

    /**
     * 获取所有操作员信息
     */
    @Override
    public List<Admin> getAdminsByNameLike(String keywords) {
        //模糊查询
        List<Admin> admins = adminMapper.selectByNameLike(keywords);
        //将密码置空
        admins.forEach(t -> t.setPassword(null));
        return admins;
    }

    /**
     * 修改操作员角色
     *
     * @param adminId
     * @param rids
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public RespBean updateRolesById(Integer adminId, String rids) {
        //插入数据条数
        int insertCount = 0;

        //adminId是否存在
        if (null == adminId) {
            return RespBean.error("操作失败，该操作员不存在");
        }

        Admin admin = adminMapper.selectById(adminId);

        //判断操作员是否存在
        if (null == admin) {
            return RespBean.error("操作失败，该操作员不存在");
        }

        //不能修改管理员的角色
        //根据adminId查询角色
        List<Role> roleList = roleMapper.getRolesByAdminId(adminId);
        roleList.forEach(t -> {
            AssertUtil.isTrue(ADMIN_ROLE_ZH.equals(t.getNameZh()), "您无权修改其他管理员！");
        });

        //如果角色被禁用
        if (!admin.getEnabled()) {
            return RespBean.error("角色修改失败，该角色已被禁用");
        }

        //获取该用户下权限的个数
        Integer count = adminRoleMapper.getCountByAdminId(adminId);

        //删除该用户下所有角色
        Integer sum = adminRoleMapper.deleteByAdminId(adminId);
        //如果角色未清空
        AssertUtil.isTrue(count != sum, "角色修改失败,该账户下角色未清空");

        //如果角色列表不为空
        if (null != rids && !"".equals(rids)) {
            String[] ridsStr = rids.split(",");
            System.out.println("ridsStr:" + ridsStr);
            //新建一个adminRole对象
            AdminRole adminRole = new AdminRole();
            //设置adminId
            adminRole.setAdminId(adminId);
            //遍历权限列表
            for (String rid : ridsStr) {
                //设置权限
                adminRole.setRid(Integer.parseInt(rid));
                //保存权限
                adminRoleMapper.insertAdminRole(adminRole);
                insertCount++;
            }
            AssertUtil.isTrue(insertCount < ridsStr.length, "用户角色绑定失败");

        } else {
            //若角色表为空则设置默认权限
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(adminId);
            adminRole.setRid(8);
            adminRoleMapper.insertAdminRole(adminRole);
        }
        //删除改角色下的菜单
        redisTemplate.delete("menu_" + adminId);
        return RespBean.success("角色修改成功");
    }

    /**
     * 修改操作员启用状态
     *
     * @param i
     * @param adminId
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public RespBean updateEnableStatus(int i, Integer adminId) {
        //不能修改管理员的角色
        //根据adminId查询角色
        List<Role> roleList = roleMapper.getRolesByAdminId(adminId);
        roleList.forEach(t -> {
            AssertUtil.isTrue(ADMIN_ROLE_ZH.equals(t.getNameZh()), "您无权修改其他管理员！");
        });
        Integer updatedNums = adminMapper.updateEnableStatus(i, adminId);
        AssertUtil.isTrue(updatedNums < 1, "操作员状态禁用状态修改失败");
        return RespBean.success("修改成功");
    }

    /**
     * 根据id删除操作员
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public RespBean deleteAdminById(Integer id) {
        //不能删除管理员
        List<Role> roleList = roleMapper.getRolesByAdminId(id);
        roleList.forEach(t -> {
            AssertUtil.isTrue(ADMIN_ROLE_ZH.equals(t.getNameZh()), "您不能删除管理员！");
        });

        Integer sums = adminMapper.updateIsActiveById(id);
        AssertUtil.isTrue(sums != 1, "操作员删除失败！");
        return RespBean.success("删除成功");
    }

    /**
     * 修改个人信息
     *
     * @param admin
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public RespBean updateAdminInfo(UpdUserParam admin) {
        List<String> address = admin.getAddress();
        StringBuffer add = new StringBuffer();
        for (String s : address) {
            if (StringUtils.isNotBlank(s)) {
                if (StringUtils.isBlank(add.toString())) {
                    add.append(s);
                } else {
                    add.append("_" + s);
                }
            }
        }
        admin.setAdd(add.toString());

        //修改个人信息
        Integer sum = adminMapper.updateAdminInfo(admin);
//        AssertUtil.isTrue(sum != 1, "修改失败");
        return RespBean.success("修改成功");
    }

    /**
     * 修改密码
     *
     * @param ruleForm
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public RespBean updatePwdById(Map<String, Object> ruleForm) {
        //ruleForm非空
        AssertUtil.isTrue(null == ruleForm, "密码不能为空");
        //[pass, checkPass, oldPass, adminId]
        String password = (String) ruleForm.get("pass");
        String checkPass = (String) ruleForm.get("checkPass");
        String oldPass = (String) ruleForm.get("oldPass");
        Integer adminId = (Integer) ruleForm.get("adminId");
        AssertUtil.isTrue(null == adminId, "用户id不能为空");
        AssertUtil.isTrue(null == password || null == checkPass || oldPass == null, "密码不能为空");
        AssertUtil.isTrue("".equals(password) || "".equals(checkPass) || "".equals(oldPass), "密码不能为空");
        AssertUtil.isTrue(!password.equals(checkPass), "密码和确认密码不相等");

        AssertUtil.isTrue(password.equals(oldPass), "新密码不能和旧密码相等");
        Admin admin = adminMapper.selectById(adminId);
        AssertUtil.isTrue(null == admin, "该用户不存在");

        AssertUtil.isTrue(!passwordEncoder.matches(oldPass, admin.getPassword()), "原始密码错误");

        //加密新密码
        String encodePwd = passwordEncoder.encode(password);
        //修改密码
        Integer nums = adminMapper.updatePwdById(encodePwd, adminId);
        AssertUtil.isTrue(1 != nums, "密码修改失败");
        return RespBean.success("密码修改成功");
    }

    /**
     * 修改头像
     *
     * @param file
     * @param userName
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public RespBean changeUserFace(MultipartFile file, String userName) {
        //上传文件到cos
        String url = fileUploadService.fileUpload(file);
        AssertUtil.isTrue(null == url || "".equals(url), "头像上传失败");
        //保存图片的url
        Integer num = adminMapper.uploadUserFaceUrl(this.path + url, userName);
        AssertUtil.isTrue(num != 1, "图片保存失败");
        return RespBean.success("保存成功", this.path + url);
    }

    /**
     * 通过关键字获取所有admin
     *
     * @param data
     * @return
     */
    @Override
    public List<Admin> getAllAdmins(String data) {
        return adminMapper.getAllAdmins(((Admin) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getId(), data);
    }

    /**
     * 注册
     * 生成八位数账号，并且使用自定义random限定，将id带有多个相同的过滤掉，之后将使用特定的用户才可以获取到好的号码。
     *
     * @param admin
     * @param request
     * @return
     */
    @Override
    @Transactional
    public String register(AdminParam admin, HttpServletRequest request) {
        //获取内容
        String captcha = (String) request.getSession().getAttribute("captcha");
        System.out.println(captcha);
        if (StringUtils.isBlank(captcha))
            throw new MyException("验证码已过期!");
        //忽略大小写进行比对
        if (StringUtils.isBlank(admin.getCode()) || !captcha.equals(admin.getCode())) {
            throw new MyException("验证码填写错误！");
        }
        if (!admin.getConfirmPassword().equals(admin.getPassword()))
            throw new MyException("两次密码不一致！");
        String userNameByEmail = adminMapper.getUserNameByEmail(admin.getEmail());
        if (StringUtils.isNotBlank(userNameByEmail))
            throw new MyException("当前邮箱已注册过！账号为：" + userNameByEmail);
        //用于测试阶段，如果用户不自己输入用户名，那么将由电脑自己生成
        if (StringUtils.isBlank(admin.getUsername())) {
            //查询出所有当前已经注册的账号，判断账号是否已经存在
            List<String> allUserName = adminMapper.getAllUserName();
            admin.setUsername(AnyUtil.getRandom(allUserName));
            System.out.println(admin.getUsername());
        }
        admin.setPassword(passwordEncoder.encode(admin.getPassword()));
        adminMapper.register(admin);
        if (admin.getUserOrAdmin().equals("user")) {
            adminRoleMapper.insertAdminRole(new AdminRole(null, admin.getId(), 8));
        } else {
            adminRoleMapper.insertAdminRole(new AdminRole(null, admin.getId(), 6));
        }
        return admin.getUsername();
    }

    /**
     * 验证发送邮箱的验证码，和密码
     *
     * @param backPasswordParam
     */
    @Override
    public void getBackPassword(BackPasswordParam backPasswordParam) {
        String emailCodeRedis = String.valueOf(redisTemplate.opsForValue().get(backPasswordParam.getEmail()));

        if ("null".equals(emailCodeRedis))
            throw new MyException("验证码已失效！");

        if (!emailCodeRedis.equals(backPasswordParam.getEmailCode()))
            throw new MyException("您输入的验证码不对！");

        if (!backPasswordParam.getPassword().equals(backPasswordParam.getConfirmPassword()))
            throw new MyException("两次密码不一致！");

        String userName = adminMapper.getUserNameByEmail(backPasswordParam.getEmail());

        if (StringUtils.isBlank(userName))
            throw new MyException("当前邮箱并未绑定用户！");

        //修改密码
        int i = adminMapper.updPasswordByUserNameAndEmail(
                passwordEncoder.encode(backPasswordParam.getPassword()),
                userName,
                backPasswordParam.getEmail());

    }
}

